﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
using MQTTnet;
using MQTTnet.Client;
using MQTTnet.Protocol;
using Models;
using DbControl;
using Common;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using static System.Net.Mime.MediaTypeNames;
using System.Windows.Markup;

namespace CentralMonitoring
{ 
    /// <summary>
    /// 扩展EventArgs的类来存储通信数据
    /// </summary>
    public class SensorEventArgs : EventArgs
    {
        public sensordatas sensordatas { get; set; } //通信数据解析后存储
    }
    public class lMqttClient
    {
        private MqttClient mqttClient = null;
        public bool IsClose { get; set; } = false;
        /// <summary>
        /// 委托事件
        /// </summary>
        public event EventHandler<SensorEventArgs> SensorChanged;
        public bool isConnected { get; set; }=false;
        #region  通信部分
        private void ConnectMqttServer()
        {
            MqttFactory mqttFactory = new MqttFactory();
            if (mqttClient == null)
            {
                mqttClient = (MqttClient)mqttFactory.CreateMqttClient();
                mqttClient.ApplicationMessageReceivedAsync += MqttClient_ApplicationMessageReceivedAsync;
                mqttClient.ConnectedAsync += MqttClient_ConnectedAsync;
                mqttClient.DisconnectedAsync += MqttClient_DisconnectedAsync;
            }
            ConnectToServer();
        }
        public async void InitMqttServer()
        {
            try
            {
                Task.Run(async () => { ConnectMqttServer(); });
            }
            catch (Exception ex)
            {
                MessageBox.Show("服务启动失败，清重启", "提示");
                lLogWrite.WriteLog("启动服务失败!" + ex.ToString());
            }

        }
        private async void ConnectToServer()
        {
            try
            {
                var mqttClientOptions = new MqttClientOptionsBuilder()
                    .WithTcpServer(session.mServerIp, session.mServerPort) 
                    .WithProtocolVersion(MQTTnet.Formatter.MqttProtocolVersion.V311)
                    .WithClientId(session.mClientUUID + Guid.NewGuid().ToString().Substring(0,6))// + Guid.NewGuid().ToString()"MonitoringApp"
                    .WithCleanSession(false)
                    .WithKeepAlivePeriod(TimeSpan.FromSeconds(30))
                    .WithCredentials("test", "test")
                    .Build();

                var res = await mqttClient.ConnectAsync(mqttClientOptions);
            }
            catch (Exception ex)
            {
                //Invoke(new Action(() =>
                //{
                //    StatusLabel1.Text = "状态:连接失败!";
                //    
                //}));
                lLogWrite.WriteLog("连接失败原因:" + ex.Message);
            }
        }
        private Task MqttClient_DisconnectedAsync(MqttClientDisconnectedEventArgs arg)
        {
            if (!IsClose)
            {
                //Invoke(new Action(() =>
                //{
                //    StatusLabel1.Text = "状态:已断开";
                //}));
                //Invoke(new Action(() =>
                //{
                //    StatusLabel1.Text = "状态:重连中";
                //    lLogWrite.WriteLog("###断开重连###");
                //    ConnectToServer();
                //}));
                lLogWrite.WriteLog("###断开重连###");
                isConnected = false;
                ConnectToServer();
            }
            return Task.CompletedTask;

        }
        private Task MqttClient_ConnectedAsync(MqttClientConnectedEventArgs arg)
        {
            //Invoke(new Action(() =>
            //{
            //    StatusLabel1.Text = "状态:已连接";

            //}));
            foreach (Devicelist vo in session.m_dvList)
            {
                if (!string.IsNullOrEmpty(vo.topic))
                {
                    string topic = vo.topic;
                    mqttClient.SubscribeAsync(topic);
                }
            }
            isConnected = true;
            return Task.CompletedTask;
        }
        /// <summary>
        /// 订阅
        /// </summary>
        /// <param name="topic"></param>
        public void Subscribe(string topic)
        {
            if (mqttClient.IsConnected)
                mqttClient.SubscribeAsync(topic);
        }
        /// <summary>
        /// 关闭
        /// </summary>
        public void Close()
        {
            if (mqttClient != null && mqttClient.IsConnected)
            {
                IsClose = true;
                mqttClient.DisconnectAsync();
                mqttClient.Dispose();
            }
        }
        private Task MqttClient_ApplicationMessageReceivedAsync(MqttApplicationMessageReceivedEventArgs arg)
        {
            string orgmsg = System.Text.Encoding.Default.GetString(arg.ApplicationMessage.Payload);
            string topic = arg.ApplicationMessage.Topic;
            lLogWrite.WriteTopicLog(topic, orgmsg);
            sensordatas orgvo = msgToVo(orgmsg,topic);
            if (orgvo != null)
            {
                SensorEventArgs sensorEventArgs = new SensorEventArgs();
                sensorEventArgs.sensordatas = orgvo;
                SensorChanged(this, sensorEventArgs);
            }          

            return Task.CompletedTask;
        }
        #endregion
        #region 因联协议标准
        private sensordatas msgToVo(string msg)
        {
            sensordatas vo = new sensordatas();
            try
            {
                if (msg.IndexOf("report_type") > 0)
                {
                    if (msg.IndexOf('}') > 0)
                    {
                        int index = msg.LastIndexOf('}');
                        if (index > 0)
                        {
                            msg = msg.Substring(0, index + 1);
                        }
                        JObject relVo = (JObject)JsonConvert.DeserializeObject(msg);
                        if (relVo != null)
                        {
                            if (relVo["report_type"].ToString() == "203")
                            {
                                string strdatas = relVo["data"].ToString();
                                dataVo datas = JsonConvert.DeserializeObject<dataVo>(strdatas);
                                if (datas != null)
                                {
                                    List<listItem> list = datas.data_list;
                                    foreach (listItem kv in list)
                                    {
                                        #region 类转化
                                        switch (kv.key)
                                        {
                                            case "Fe1":
                                                vo.fe1 = int.Parse(kv.data);
                                                break;
                                            case "Fe2":
                                                vo.fe2 = int.Parse(kv.data);
                                                break;
                                            case "Fe3":
                                                vo.fe3 = int.Parse(kv.data);
                                                break;
                                            case "Fe4":
                                                vo.fe4 = int.Parse(kv.data);
                                                break;
                                            case "Fe5":
                                                vo.fe5 = int.Parse(kv.data);
                                                break;
                                            case "Fe6":
                                                vo.fe6 = int.Parse(kv.data);
                                                break;
                                            case "Fe7":
                                                vo.fe7 = int.Parse(kv.data);
                                                break;
                                            case "Fe8":
                                                vo.fe8 = int.Parse(kv.data);
                                                break;
                                            case "Fe9":
                                                vo.fe9 = int.Parse(kv.data);
                                                break;
                                            case "Fe10":
                                                vo.fe10 = int.Parse(kv.data);
                                                break;                                          
                                            case "NFe1":
                                                vo.nfe1 = int.Parse(kv.data);
                                                break;
                                            case "NFe2":
                                                vo.nfe2 = int.Parse(kv.data);
                                                break;
                                            case "NFe3":
                                                vo.nfe3 = int.Parse(kv.data);
                                                break;
                                            case "NFe4":
                                                vo.nfe4 = int.Parse(kv.data);
                                                break;
                                            case "Mo":
                                                vo.ppm = decimal.Parse(kv.data);
                                                break;
                                            case "Vis":
                                                {
                                                    decimal v = 0;
                                                    if (decimal.TryParse(kv.data, out v))
                                                    {
                                                        vo.vis = v;
                                                    }
                                                    else
                                                    {
                                                        vo.vis = 1119;
                                                    }
                                                }
                                                break;
                                            case "Dens":
                                                vo.dens = decimal.Parse(kv.data);
                                                break;
                                            case "Diel":
                                                vo.diel = decimal.Parse(kv.data);
                                                break;
                                            case "Temp":
                                                vo.temper = decimal.Parse(kv.data);
                                                break;
                                        }
                                        #endregion
                                    }
                                    vo.device_code = datas.mac;                                  
                                    vo.create_time = DateTime.Now;// TimestampHelper.GetDateTime(datas.daq_time);
                                }
                            }
                        }
                    }
                }
            }
            catch (Exception ex)
            {
                lLogWrite.WriteLog("解析error:" + ex.ToString());
                vo = null;
            }
            return vo;

        }
        private sensordatas msgToVo(string msg, string topic)
        {
            sensordatas vo = new sensordatas();
            try
            {
                if (msg.IndexOf("report_type") > 0)//解析YinL协议
                {
                    if (msg.IndexOf('}') > 0)
                    {
                        int leftindex = msg.IndexOf('{');
                        if (leftindex > -1)
                        {
                            msg = msg.Substring(leftindex, msg.Length - leftindex);
                        }
                        int index = msg.LastIndexOf('}');
                        if (index > 0)
                        {
                            msg = msg.Substring(0, index + 1);
                        }
                        JObject relVo = (JObject)JsonConvert.DeserializeObject(msg);
                        if (relVo != null)
                        {
                            if (relVo["report_type"].ToString() == "203")
                            {
                                string strdatas = relVo["data"].ToString();
                                dataVo datas = JsonConvert.DeserializeObject<dataVo>(strdatas);
                                if (datas != null)
                                {
                                    List<listItem> list = datas.data_list;
                                    foreach (listItem kv in list)
                                    {
                                        decimal tmp_dm = 0m;
                                        int tmp_int = 0;
                                        #region 类转化
                                        switch (kv.key)
                                        {
                                            case "Fe1":
                                                if (int.TryParse(kv.data, out tmp_int))
                                                    vo.fe1 = int.Parse(kv.data);
                                                break;
                                            case "Fe2":
                                                if (int.TryParse(kv.data, out tmp_int))
                                                    vo.fe2 = int.Parse(kv.data);
                                                break;
                                            case "Fe3":
                                                if (int.TryParse(kv.data, out tmp_int))
                                                    vo.fe3 = int.Parse(kv.data);
                                                break;
                                            case "Fe4":
                                                if (int.TryParse(kv.data, out tmp_int))
                                                    vo.fe4 = int.Parse(kv.data);
                                                break;
                                            case "Fe5":
                                                if (int.TryParse(kv.data, out tmp_int))
                                                    vo.fe5 = int.Parse(kv.data);
                                                break;
                                            case "Fe6":
                                                if (int.TryParse(kv.data, out tmp_int))
                                                    vo.fe6 = int.Parse(kv.data);
                                                break;
                                            case "Fe7":
                                                if (int.TryParse(kv.data, out tmp_int))
                                                    vo.fe7 = int.Parse(kv.data);
                                                break;
                                            case "Fe8":
                                                if (int.TryParse(kv.data, out tmp_int))
                                                    vo.fe8 = int.Parse(kv.data);
                                                break;
                                            case "Fe9":
                                                if (int.TryParse(kv.data, out tmp_int))
                                                    vo.fe9 = int.Parse(kv.data);
                                                break;
                                            case "Fe10":
                                                if (int.TryParse(kv.data, out tmp_int))
                                                    vo.fe10 = int.Parse(kv.data);
                                                break;
                                            case "ZFe":
                                                if (int.TryParse(kv.data, out tmp_int))
                                                    vo.fe = int.Parse(kv.data);
                                                break;
                                            case "NFe1":
                                                if (int.TryParse(kv.data, out tmp_int))
                                                    vo.nfe1 = int.Parse(kv.data);
                                                break;
                                            case "NFe2":
                                                if (int.TryParse(kv.data, out tmp_int))
                                                    vo.nfe2 = int.Parse(kv.data);
                                                break;
                                            case "NFe3":
                                                if (int.TryParse(kv.data, out tmp_int))
                                                    vo.nfe3 = int.Parse(kv.data);
                                                break;
                                            case "NFe4":
                                                if (int.TryParse(kv.data, out tmp_int))
                                                    vo.nfe4 = int.Parse(kv.data);
                                                break;
                                            case "ZNFe":
                                                if (int.TryParse(kv.data, out tmp_int))
                                                    vo.nfe = int.Parse(kv.data);
                                                break;
                                            case "Mo":                                              
                                                if(decimal.TryParse(kv.data ,out tmp_dm))
                                                    vo.mo = decimal.Parse(kv.data);
                                                break;
                                            case "Vis":
                                                if (decimal.TryParse(kv.data, out tmp_dm))
                                                    vo.vis = decimal.Parse(kv.data);
                                                break;
                                            case "Dens":
                                                if (decimal.TryParse(kv.data, out tmp_dm))
                                                    vo.dens = decimal.Parse(kv.data);
                                                break;
                                            case "Diel":
                                                if (decimal.TryParse(kv.data, out tmp_dm))
                                                    vo.diel = decimal.Parse(kv.data);
                                                break;
                                            case "Temp":
                                                if (decimal.TryParse(kv.data, out tmp_dm))
                                                    vo.temper = decimal.Parse(kv.data);
                                                break;
                                            case "Vis40":
                                                if (decimal.TryParse(kv.data, out tmp_dm))
                                                    vo.vis40=decimal.Parse(kv.data);
                                                break;
                                            case  "PPM":
                                                if (decimal.TryParse(kv.data, out tmp_dm))
                                                    vo.ppm = decimal.Parse(kv.data);
                                                break;
                                            case "Aw":
                                                if (decimal.TryParse(kv.data, out tmp_dm))
                                                    vo.aw = decimal.Parse(kv.data);
                                                break;
                                            case "Conc4um":
                                                if (int.TryParse(kv.data, out tmp_int))
                                                    vo.par1 = int.Parse(kv.data);
                                                break;
                                            case "Conc6um":
                                                if (int.TryParse(kv.data, out tmp_int))
                                                    vo.par2 = int.Parse(kv.data);
                                                break;
                                            case "Conc14um":
                                                if (int.TryParse(kv.data, out tmp_int))
                                                    vo.par3 = int.Parse(kv.data);
                                                break;
                                            case "Conc21um":
                                                if (int.TryParse(kv.data, out tmp_int))
                                                    vo.par4 = int.Parse(kv.data);
                                                break;
                                            case "ISO4um":
                                                if (int.TryParse(kv.data, out tmp_int))
                                                    vo.class1 = int.Parse(kv.data);
                                                break;
                                            case "ISO6um":
                                                if (int.TryParse(kv.data, out tmp_int))
                                                    vo.class2 = int.Parse(kv.data);
                                                break;
                                            case "ISO14um":
                                                if (int.TryParse(kv.data, out tmp_int))
                                                    vo.class3 = int.Parse(kv.data);
                                                break;
                                            case "ISO21um":
                                                if (int.TryParse(kv.data, out tmp_int))
                                                    vo.class4 = int.Parse(kv.data);
                                                break;
                                            case "PLvNas":
                                                if(int.TryParse(kv.data, out tmp_int))
                                                    vo.class_total = int.Parse(kv.data);
                                                break;
                                            case "PLvIso":
                                                if(int.TryParse(kv.data,out tmp_int))
                                                    vo.class6 = int.Parse(kv.data);
                                                break;
                                        }
                                        #endregion
                                    }
                                    if (topic.Contains("D2022001"))
                                    {
                                        datas.mac = datas.mac.Replace("mmjsj_01", "mmhlj_01");
                                    }
                                    else if (topic.Contains("DG2022032"))
                                    {
                                        datas.mac = datas.mac.Replace("snmjsj_1", "qysnmjsj_1");
                                    }
                                    else if (topic.Contains("DG2022027"))
                                    {
                                        datas.mac = datas.mac.Replace("snmjsj_2", "qysnmjsj_2");
                                    }
                                    else if (topic.Contains("DG2022030"))
                                    {
                                        datas.mac = datas.mac.Replace("hzyjsj_1", "qyhzyjsj_1");
                                    }
                                    else if (topic.Contains("DG2022024"))
                                    {
                                        datas.mac = datas.mac.Replace("slmjsj_1", "qyslmjsj_1");
                                    }
                                    vo.device_code = datas.mac;
                                    vo.create_time = DateTime.Now;// TimestampHelper.GetDateTime(datas.daq_time);
                                }
                            }
                        }
                    }
                }
                else if (msg.IndexOf("Y001") > 0)//解析ZhXin协议
                {
                    int index = msg.IndexOf('}');
                    if (msg.IndexOf('}') > 0)
                    {
                        index = msg.LastIndexOf('}');
                        if (index > 0)
                        {
                            msg = msg.Substring(0, index + 1);
                        }
                        ZhXinVo zhXinVo = JsonConvert.DeserializeObject<ZhXinVo>(msg);
                        if (zhXinVo.deviceid != null)
                        {
                            string sn = zhXinVo.deviceid;                            
                            vo.device_code = sn;
                            vo.temper = zhXinVo.msg.data.Y004;
                            vo.vis = zhXinVo.msg.data.Y002;
                            vo.dens = zhXinVo.msg.data.Y003;
                            vo.diel = zhXinVo.msg.data.Y001;
                            vo.ppm = zhXinVo.msg.data.Y025;
                            vo.aw = zhXinVo.msg.data.Y031;
                            vo.fe1 = zhXinVo.msg.data.Y005;
                            vo.fe2 = zhXinVo.msg.data.Y007;
                            vo.fe3 = zhXinVo.msg.data.Y009;
                            vo.fe4 = zhXinVo.msg.data.Y011;
                            vo.fe5 = zhXinVo.msg.data.Y013;
                            vo.fe6 = zhXinVo.msg.data.Y015;
                            vo.fe7 = zhXinVo.msg.data.Y017;
                            vo.fe8 = zhXinVo.msg.data.Y019;
                            vo.fe9 = zhXinVo.msg.data.Y021;
                            vo.fe10 = zhXinVo.msg.data.Y023;
                            vo.nfe1 = zhXinVo.msg.data.Y027;
                            vo.nfe2 = zhXinVo.msg.data.Y028;
                            vo.nfe3 = zhXinVo.msg.data.Y029;
                            vo.nfe4 = zhXinVo.msg.data.Y030;
                            vo.vis40 = zhXinVo.msg.data.Y054;
                         
                            if (string.IsNullOrEmpty(zhXinVo.ts))
                            {
                                vo.create_time = DateTime.Now;
                            }
                            else
                            {
                                long times = long.Parse(zhXinVo.ts);
                                vo.create_time = TimestampHelper.GetDateTime(times);
                            }

                        }
                    }
                }
            }
            catch (Exception ex)
            {
                lLogWrite.WriteLog("解析error:" + ex.ToString());
                vo = null;
            }
            return vo;

        }       
        #endregion
    }
}
